﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Diagnostics;
using System.Collections;

namespace AndersLiu.PE
{
    public enum TableIndex : uint
    {
        Module = 0x00,
        TypeRef = 0x01,
        TypeDef = 0x02,
        FieldPtr = 0x03,
        Field = 0x04,
        MethodPtr = 0x05,
        MethodDef = 0x06,
        ParamPtr = 0x07,
        Param = 0x08,
        InterfaceImpl = 0x09,
        MemberRef = 0x0A,
        Constant = 0x0B,
        CustomAttribute = 0x0C,
        FieldMarshal = 0x0D,
        DeclSecurity = 0x0E,
        ClassLayout = 0x0F,
        FieldLayout = 0x10,
        StandAloneSig = 0x11,
        EventMap = 0x12,
        EventPtr = 0x13,
        Event = 0x14,
        PropertyMap = 0x15,
        PropertyPtr = 0x16,
        Property = 0x17,
        MethodSemantics = 0x18,
        MethodImpl = 0x19,
        ModuleRef = 0x1A,
        TypeSpec = 0x1B,
        ImplMap = 0x1C,
        FieldRva = 0x1D,
        EncLog = 0x1E,
        EncMap = 0x1F,
        Assembly = 0x20,
        AssemblyProcessor = 0x21,
        AssemblyOS = 0x22,
        AssemblyRef = 0x23,
        AssemblyRefProcessor = 0x24,
        AssemblyRefOS = 0x25,
        File = 0x26,
        ExportedType = 0x27,
        ManifestResource = 0x28,
        NestedClass = 0x29,
        GenericParam = 0x2A,
        MethodSpec = 0x2B,
        GenericParamConstraint = 0x2C,

        MaxTables = 0x2D,

        String = 0x70,
    }

    public class TableNames
    {
        public const string Module = "Module";
        public const string TypeRef = "TypeRef";
        public const string TypeDef = "TypeDef";
        public const string FieldPtr = "FieldPtr";
        public const string Field = "Field";
        public const string MethodPtr = "MethodPtr";
        public const string MethodDef = "MethodDef";
        public const string ParamPtr = "ParamPtr";
        public const string Param = "Param";
        public const string InterfaceImpl = "InterfaceImpl";
        public const string MemberRef = "MemberRef";
        public const string Constant = "Constant";
        public const string CustomAttribute = "CustomAttribute";
        public const string FieldMarshal = "FieldMarshal";
        public const string DeclSecurity = "DeclSecurity";
        public const string ClassLayout = "ClassLayout";
        public const string FieldLayout = "FieldLayout";
        public const string StandAloneSig = "StandAloneSig";
        public const string EventMap = "EventMap";
        public const string EventPtr = "EventPtr";
        public const string Event = "Event";
        public const string PropertyMap = "PropertyMap";
        public const string PropertyPtr = "PropertyPtr";
        public const string Property = "Property";
        public const string MethodSemantics = "MethodSemantics";
        public const string MethodImpl = "MethodImpl";
        public const string ModuleRef = "ModuleRef";
        public const string TypeSpec = "TypeSpec";
        public const string ImplMap = "ImplMap";
        public const string FieldRva = "FieldRva";
        public const string EncLog = "EncLog";
        public const string EncMap = "EncMap";
        public const string Assembly = "Assembly";
        public const string AssemblyProcessor = "AssemblyProcessor";
        public const string AssemblyOS = "AssemblyOS";
        public const string AssemblyRef = "AssemblyRef";
        public const string AssemblyRefProcessor = "AssemblyRefProcessor";
        public const string AssemblyRefOS = "AssemblyRefOS";
        public const string File = "File";
        public const string ExportedType = "ExportedType";
        public const string ManifestResource = "ManifestResource";
        public const string NestedClass = "NestedClass";
        public const string GenericParam = "GenericParam";
        public const string MethodSpec = "MethodSpec";
        public const string GenericParamConstraint = "GenericParamConstraint";

        public static string Get(TableIndex index)
        {
            return _allNames[(int)index];
        }

        static string[] _allNames = new[]
        {
            Module,
            TypeRef,
            TypeDef,
            FieldPtr,
            Field,
            MethodPtr,
            MethodDef,
            ParamPtr,
            Param,
            InterfaceImpl,
            MemberRef,
            Constant,
            CustomAttribute,
            FieldMarshal,
            DeclSecurity,
            ClassLayout,
            FieldLayout,
            StandAloneSig,
            EventMap,
            EventPtr,
            Event,
            PropertyMap,
            PropertyPtr,
            Property,
            MethodSemantics,
            MethodImpl,
            ModuleRef,
            TypeSpec,
            ImplMap,
            FieldRva,
            EncLog,
            EncMap,
            Assembly,
            AssemblyProcessor,
            AssemblyOS,
            AssemblyRef,
            AssemblyRefProcessor,
            AssemblyRefOS,
            File,
            ExportedType,
            ManifestResource,
            NestedClass,
            GenericParam,
            MethodSpec,
            GenericParamConstraint,
        };
    }

    public class TableHeader : ImageData
    {
        public U4Field Reserved { get; private set; }
        public U1Field MajorVersion { get; private set; }
        public U1Field MinorVersion { get; private set; }
        public U1Field HeapSizes { get; private set; }
        public U1Field Reserved2 { get; private set; }
        public U8Field Valid { get; private set; }
        public U8Field Sorted { get; private set; }
        public U4Vector Rows { get; private set; }

        public bool IsTableValid(TableIndex tid)
        {
            var tableBit = (ulong)1 << (int)tid;
            return (this.Valid.Value & tableBit) != 0;
        }

        public bool IsTableSorted(TableIndex tid)
        {
            var tableBit = (ulong)1 << (int)tid;
            return (this.Sorted.Value & tableBit) != 0;
        }

        public uint GetTableRowCount(TableIndex tid)
        {
            var i = (uint)tid;

            if (i >= TableStream.NumberOfTables)
                return 0; //throw new InvalidTableIndexException();

            return _tableRows[i];
        }

        public uint GetRidFieldSize(TableIndex tid)
        {
            var rows = GetTableRowCount(tid);
            return (uint)(rows <= ushort.MaxValue ? 2 : 4);
        }

        public uint GetStringsStreamIndexFieldSize()
        {
            return (uint)((this.HeapSizes.Value & 0x01) == 0 ? 2 : 4);
        }

        public uint GetGuidStreamIndexFieldSize()
        {
            return (uint)((this.HeapSizes.Value & 0x02) == 0 ? 2 : 4);
        }

        public uint GetBlobStreamIndexFieldSize()
        {
            return (uint)((this.HeapSizes.Value & 0x04) == 0 ? 2 : 4);
        }

        public uint GetCodedTokenFieldSize(CodedTokenIndex ctid)
        {
            var maxRid = (uint)0xFFFF >> ctid.TagSize;
            for (var i = 0; i < ctid.ReferencedTables.Length; i++)
            {
                if (GetTableRowCount(ctid.ReferencedTables[i]) > maxRid)
                    return 4;
            }

            return 2;
        }

        public uint GetTableItemSize(TableIndex tid)
        {
            switch (tid)
            {
                case TableIndex.Module:
                    // Generation  USHORT
                    // Name        STRING
                    // Mvid        GUID
                    // EncId       GUID
                    // EncBaseId   GUID
                    return
                        2 +
                        GetStringsStreamIndexFieldSize() +
                        GetGuidStreamIndexFieldSize() +
                        GetGuidStreamIndexFieldSize() +
                        GetGuidStreamIndexFieldSize();

                case TableIndex.TypeRef:
                    // ResolutionScope  ResolutionScope
                    // Name             STRING
                    // Namespace        STRING
                    return
                        GetCodedTokenFieldSize(CodedTokenIndex.ResolutionScope) +
                        GetStringsStreamIndexFieldSize() +
                        GetStringsStreamIndexFieldSize();

                case TableIndex.TypeDef:
                    // Flags       ULONG
                    // Name        STRING
                    // Namespace   STRING
                    // Extends     TypeDefOrRef
                    // FieldList   RID: Field
                    // MethodList  RID: Method
                    return
                        4 +
                        GetStringsStreamIndexFieldSize() +
                        GetStringsStreamIndexFieldSize() +
                        GetCodedTokenFieldSize(CodedTokenIndex.TypeDefOrRef) +
                        GetRidFieldSize(TableIndex.Field) +
                        GetRidFieldSize(TableIndex.MethodDef);

                case TableIndex.FieldPtr:
                    // Field  RID: Field
                    return
                        GetRidFieldSize(TableIndex.Field);

                case TableIndex.Field:
                    // Flags      USHORT
                    // Name       STRING
                    // Signature  BLOB
                    return
                        2 +
                        GetStringsStreamIndexFieldSize() +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.MethodPtr:
                    // Method  RID: Method
                    return
                        GetRidFieldSize(TableIndex.MethodDef);

                case TableIndex.MethodDef:
                    // RVA        ULONG
                    // ImplFlags  USHORT
                    // Flags      USHORT
                    // Name       STRING
                    // Signature  BLOB
                    // ParamList  RID: Param
                    return
                        4 +
                        2 +
                        2 +
                        GetStringsStreamIndexFieldSize() +
                        GetBlobStreamIndexFieldSize() +
                        GetRidFieldSize(TableIndex.Param);

                case TableIndex.ParamPtr:
                    // Param  RID: Param
                    return
                        GetRidFieldSize(TableIndex.Param);

                case TableIndex.Param:
                    // Flags     USHORT
                    // Sequence  USHORT
                    // Name      STRING
                    return
                        2 +
                        2 +
                        GetStringsStreamIndexFieldSize();

                case TableIndex.InterfaceImpl:
                    // Class      RID: TypeDef
                    // Interface  TypeDefOrRef
                    return
                        GetRidFieldSize(TableIndex.TypeDef) +
                        GetCodedTokenFieldSize(CodedTokenIndex.TypeDefOrRef);

                case TableIndex.MemberRef:
                    // Class      MemberRefParent
                    // Name       STRING
                    // Signature  BLOB
                    return
                        GetCodedTokenFieldSize(CodedTokenIndex.MemberRefParent) +
                        GetStringsStreamIndexFieldSize() +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.Constant:  // !!!!!!!!!!1
                    // Type           BYTE
                    // (PaddingZero)  BYTE    // padding zero
                    // Parent         HasConstant
                    // Value          BLOB
                    return
                        1 +
                        1 +
                        GetCodedTokenFieldSize(CodedTokenIndex.HasConstant) +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.CustomAttribute:
                    // Parent  HasCustomAttribute
                    // Type    CustomAttributeType
                    // Value   BLOB
                    return
                        GetCodedTokenFieldSize(CodedTokenIndex.HasCustomAttribute) +
                        GetCodedTokenFieldSize(CodedTokenIndex.CustomAttributeType) +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.FieldMarshal:
                    // Parent      FieldMarshal
                    // NativeType  BLOB
                    return
                        GetCodedTokenFieldSize(CodedTokenIndex.HasFieldMarshall) +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.DeclSecurity:
                    // Action         SHORT
                    // Parent         HasDeclSecurity
                    // PermissionSet  BLOB
                    return
                        2 +
                        GetCodedTokenFieldSize(CodedTokenIndex.HasDeclSecurity) +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.ClassLayout:
                    // PackingSize  USHORT
                    // ClassSize    ULONG
                    // Parent       RID: TypeDef
                    return
                        2 +
                        4 +
                        GetRidFieldSize(TableIndex.TypeDef);

                case TableIndex.FieldLayout:
                    // OffSet  ULONG
                    // Field   RID: Field
                    return
                        4 +
                        GetRidFieldSize(TableIndex.Field);

                case TableIndex.StandAloneSig:
                    // Signature  BLOB
                    return
                        GetBlobStreamIndexFieldSize();

                case TableIndex.EventMap:
                    // Parent     RID: TypeDef
                    // EventList  RID: Event
                    return
                        GetRidFieldSize(TableIndex.TypeDef) +
                        GetRidFieldSize(TableIndex.Event);

                case TableIndex.EventPtr:
                    // Event  RID: Event
                    return
                        GetRidFieldSize(TableIndex.Event);

                case TableIndex.Event:
                    // EventFlags  USHORT
                    // Name        STRING
                    // EventType   TypeDefOrRef
                    return
                        2 +
                        GetStringsStreamIndexFieldSize() +
                        GetCodedTokenFieldSize(CodedTokenIndex.TypeDefOrRef);

                case TableIndex.PropertyMap:
                    // Parent        RID: TypeDef
                    // PropertyList  RID: Property
                    return
                        GetRidFieldSize(TableIndex.TypeDef) +
                        GetRidFieldSize(TableIndex.Property);

                case TableIndex.PropertyPtr:
                    // Property  RID: Property
                    return
                        GetRidFieldSize(TableIndex.Property);

                case TableIndex.Property:
                    // PropFlags  USHORT
                    // Name       STRING
                    // Type       BLOB
                    return
                        2 +
                        GetStringsStreamIndexFieldSize() +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.MethodSemantics:
                    // Semantic     USHORT
                    // Method       RID: Method
                    // Association  HasSemantic
                    return
                        2 +
                        GetRidFieldSize(TableIndex.MethodDef) +
                        GetCodedTokenFieldSize(CodedTokenIndex.HasSemantics);

                case TableIndex.MethodImpl:
                    // Class              RID: TypeDef
                    // MethodBody         MethodDefOrRef
                    // MethodDeclaration  MethodDefOrRef
                    return
                        GetRidFieldSize(TableIndex.TypeDef) +
                        GetCodedTokenFieldSize(CodedTokenIndex.MethodDefOrRef) +
                        GetCodedTokenFieldSize(CodedTokenIndex.MethodDefOrRef);

                case TableIndex.ModuleRef:
                    // Name  STRING
                    return
                        GetStringsStreamIndexFieldSize();

                case TableIndex.TypeSpec:
                    // Signature  BLOB
                    return
                        GetBlobStreamIndexFieldSize();

                case TableIndex.ImplMap:
                    // MappingFlags     USHORT
                    // MemberForwarded  MemberForwarded
                    // ImportName       STRING
                    // ImportScope      RID: ModuleRef
                    return
                        2 +
                        GetCodedTokenFieldSize(CodedTokenIndex.MemberForwarded) +
                        GetStringsStreamIndexFieldSize() +
                        GetRidFieldSize(TableIndex.ModuleRef);

                case TableIndex.FieldRva:
                    // RVA    ULONG
                    // Field  RID: Field
                    return
                        4 +
                        GetRidFieldSize(TableIndex.Field);

                case TableIndex.EncLog:
                    // Token     ULONG
                    // FuncCode  ULONG
                    return
                        4 +
                        4;

                case TableIndex.EncMap:
                    // Token  ULONG
                    return
                        4;

                case TableIndex.Assembly:
                    // HashAlgId       ULONG
                    // MajorVersion    USHORT
                    // MinorVersion    USHORT
                    // BuildNumber     USHORT
                    // RevisionNumber  USHORT
                    // Flags           ULONG
                    // PublicKey       BLOB
                    // Name            STRING
                    // Locale          STRING
                    return
                        4 +
                        2 +
                        2 +
                        2 +
                        2 +
                        4 +
                        GetBlobStreamIndexFieldSize() +
                        GetStringsStreamIndexFieldSize() +
                        GetStringsStreamIndexFieldSize();

                case TableIndex.AssemblyProcessor:
                    // Processor  ULONG
                    return
                        4;

                case TableIndex.AssemblyOS:
                    // OSPlatformID    ULONG
                    // OSMajorVersion  ULONG
                    // OSMinorVersion  ULONG
                    return
                        4 +
                        4 +
                        4;

                case TableIndex.AssemblyRef:
                    // MajorVersion      USHORT
                    // MinorVersion      USHORT
                    // BuildNumber       USHORT
                    // RevisionNumber    USHORT
                    // Flags             ULONG
                    // PublicKeyOrToken  BLOB
                    // Name              STRING
                    // Locale            STRING
                    // HashValue         BLOB
                    return
                        2 +
                        2 +
                        2 +
                        2 +
                        4 +
                        GetBlobStreamIndexFieldSize() +
                        GetStringsStreamIndexFieldSize() +
                        GetStringsStreamIndexFieldSize() +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.AssemblyRefProcessor:
                    // Processor    ULONG
                    // AssemblyRef  RID: AssemblyRef
                    return
                        4 +
                        GetRidFieldSize(TableIndex.AssemblyRef);

                case TableIndex.AssemblyRefOS:
                    // OSPlatformId    ULONG
                    // OSMajorVersion  ULONG
                    // OSMinorVersion  ULONG
                    // AssemblyRef     RID: AssemblyRef
                    return
                        4 +
                        4 +
                        4 +
                        GetRidFieldSize(TableIndex.AssemblyRef);

                case TableIndex.File:
                    // Flags      ULONG
                    // Name       STRING
                    // HashValue  BLOB
                    return
                        4 +
                        GetStringsStreamIndexFieldSize() +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.ExportedType:
                    // Flags           ULONG
                    // TypeDefId       ULONG
                    // TypeName        STRING
                    // TypeNamespace   STRING
                    // Implementation  Implementation
                    return
                        4 +
                        4 +
                        GetStringsStreamIndexFieldSize() +
                        GetStringsStreamIndexFieldSize() +
                        GetCodedTokenFieldSize(CodedTokenIndex.Implementation);

                case TableIndex.ManifestResource:
                    // Offset          ULONG
                    // Flags           ULONG
                    // Name            STRING
                    // Implementation  Implementation
                    return
                        4 +
                        4 +
                        GetStringsStreamIndexFieldSize() +
                        GetCodedTokenFieldSize(CodedTokenIndex.Implementation);

                case TableIndex.NestedClass:
                    // NestedClass     RID: TypeDef
                    // EnclosingClass  RID: TypeDef
                    return
                        GetRidFieldSize(TableIndex.TypeDef) +
                        GetRidFieldSize(TableIndex.TypeDef);

                case TableIndex.GenericParam:
                    // Number  USHORT
                    // Flags   USHORT
                    // Owner   TypeOrMethodDef
                    // Name    STRING
                    return
                        2 +
                        2 +
                        GetCodedTokenFieldSize(CodedTokenIndex.TypeOrMethodDef) +
                        GetStringsStreamIndexFieldSize();

                case TableIndex.MethodSpec:
                    // Method         MethodDefOrRef
                    // Instantiation  BLOB
                    return
                        GetCodedTokenFieldSize(CodedTokenIndex.MethodDefOrRef) +
                        GetBlobStreamIndexFieldSize();

                case TableIndex.GenericParamConstraint:
                    // Owner       RID: GenericParam
                    // Constraint  TypeDefOrRef
                    return
                        GetRidFieldSize(TableIndex.GenericParam) +
                        GetCodedTokenFieldSize(CodedTokenIndex.TypeDefOrRef);

                default:
                    throw new NotSupportedException();
            }
        }

        internal TableHeader(PEFile image, uint offset)
            : base(image, offset)
        {
            var pos = offset;

            this.Reserved = new U4Field(image, pos);
            pos += this.Reserved.RawDataSize;

            this.MajorVersion = new U1Field(image, pos);
            pos += this.MajorVersion.RawDataSize;

            this.MinorVersion = new U1Field(image, pos);
            pos += this.MinorVersion.RawDataSize;

            this.HeapSizes = new U1Field(image, pos);
            pos += this.HeapSizes.RawDataSize;

            this.Reserved2 = new U1Field(image, pos);
            pos += this.Reserved2.RawDataSize;

            this.Valid = new U8Field(image, pos);
            pos += this.Valid.RawDataSize;

            this.Sorted = new U8Field(image, pos);
            pos += this.Sorted.RawDataSize;

            var numRows = IntUtility.Count1Bit(this.Valid.Value);

            this.Rows = new U4Vector(image, pos, numRows);
            pos += this.Rows.RawDataSize;

            SetSize(pos - offset);

            FillTableRows();
        }

        private void FillTableRows()
        {
            _tableRows = new uint[TableStream.NumberOfTables];

            var p = 0;
            var validMask = this.Valid.Value;
            var tableBit = (ulong)0;
            for (var i = 0; i < TableStream.NumberOfTables; i++)
            {
                tableBit = (ulong)1 << i;
                _tableRows[i] = (validMask & tableBit) != 0
                    ? this.Rows[p++].Value
                    : 0;
            }
        }

        private uint[] _tableRows;
    }

    public class RidField : Field<Rid>
    {
        internal RidField(PEFile image, uint offset, TableIndex tid)
            : base(image, offset, image.TableStream.TableHeader.GetRidFieldSize(tid))
        {
            _tid = tid;
        }

        protected override Rid ParseValue(byte[] rawData)
        {
            var rid = (uint)0;

            if (rawData.Length == 2)
                rid = BitConverter.ToUInt16(rawData, 0);
            else if (rawData.Length == 4)
                rid = BitConverter.ToUInt32(rawData, 0);
            else
                throw new NotSupportedException();

            return new Rid(_tid, rid);
        }

        protected override string GetValueString()
        {
            return this.Value.ToString();
        }

        private TableIndex _tid;
    }

    public class StringsStreamIndexField : Field<uint>
    {
        internal StringsStreamIndexField(PEFile image, uint offset)
            : base(image, offset, image.TableStream.TableHeader.GetStringsStreamIndexFieldSize())
        {
        }

        protected override uint ParseValue(byte[] rawData)
        {
            if (rawData.Length == 2)
                return BitConverter.ToUInt16(rawData, 0);
            else if (rawData.Length == 4)
                return BitConverter.ToUInt32(rawData, 0);
            else
                throw new NotSupportedException();
        }

        protected override string GetValueString()
        {
            if (this.Value > 0)
            {
                var refs = this.PEFile.StringsStream.GetItem(this.Value).Value;
                return string.Format("#Strings[{0}] ('{1}')", this.Value, refs);
            }
            else
            {
                return "#Strings[0]";
            }
        }
    }

    public class GuidStreamIndexField : Field<uint>
    {
        internal GuidStreamIndexField(PEFile image, uint offset)
            : base(image, offset, image.TableStream.TableHeader.GetGuidStreamIndexFieldSize())
        {
        }

        protected override uint ParseValue(byte[] rawData)
        {
            if (rawData.Length == 2)
                return BitConverter.ToUInt16(rawData, 0);
            else if (rawData.Length == 4)
                return BitConverter.ToUInt32(rawData, 0);
            else
                throw new NotSupportedException();
        }

        protected override string GetValueString()
        {
            if (this.Value > 0)
            {
                var refs = this.PEFile.GuidStream.GetItem(this.Value).Value;
                return string.Format("#GUID[{0}] ({1})", this.Value, refs);
            }
            else
            {
                return "#GUID[0]";
            }
        }
    }

    public class BlobStreamIndexField : Field<uint>
    {
        internal BlobStreamIndexField(PEFile image, uint offset)
            : base(image, offset, image.TableStream.TableHeader.GetBlobStreamIndexFieldSize())
        {
        }

        protected override uint ParseValue(byte[] rawData)
        {
            if (rawData.Length == 2)
                return BitConverter.ToUInt16(rawData, 0);
            else if (rawData.Length == 4)
                return BitConverter.ToUInt32(rawData, 0);
            else
                throw new NotSupportedException();
        }

        protected override string GetValueString()
        {
            if (this.Value > 0)
            {
                var val = this.PEFile.BlobStream.GetItem(this.Value).Blob.Value;
                var refs = BitConverter.ToString(val);
                return string.Format("#Blob[{0}] ({1})", this.Value, refs);
            }
            else
            {
                return "#Blob[0]";
            }
        }
    }

    public class CodedTokenField : Field<CodedToken>
    {
        internal CodedTokenField(PEFile image, uint offset, CodedTokenIndex ctid)
            : base(image, offset, image.TableStream.TableHeader.GetCodedTokenFieldSize(ctid))
        {
            _ctid = ctid;
        }

        protected override CodedToken ParseValue(byte[] rawData)
        {
            var codedToken = (uint)0;

            if (rawData.Length == 2)
                codedToken = BitConverter.ToUInt16(rawData, 0);
            else if (rawData.Length == 4)
                codedToken = BitConverter.ToUInt32(rawData, 0);
            else
                throw new NotSupportedException();

            return new CodedToken(_ctid, codedToken);
        }

        protected override string GetValueString()
        {
            return this.Value.ToString();
        }

        private CodedTokenIndex _ctid;
    }

    public abstract class TableItemBase : ImageData
    {
        public TableIndex TableIndex { get; private set; }

        internal TableItemBase(TableHeader th, uint offset, TableIndex tid)
            : base(th.PEFile, offset, th.GetTableItemSize(tid))
        {
            this.TableIndex = tid;
        }
    }

    public abstract class TableBase<T> : ImageData, IEnumerable<T>
        where T : TableItemBase
    {
        public T this[uint rid]
        {
            get
            {
                if (rid < 1 || rid > this.RowCount)
                    throw new ArgumentOutOfRangeException();

                var th = this.PEFile.TableStream.TableHeader;
                var offset = this.FileOffset + (rid - 1) * th.GetTableItemSize(this.TableIndex);
                return GetItem(offset);
            }
        }
        public uint RowCount { get; private set; }
        public TableIndex TableIndex { get; private set; }

        public IEnumerator<T> GetEnumerator()
        {
            for (var i = (uint)1; i <= this.RowCount; i++)
                yield return this[i];
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal TableBase(TableHeader th, uint offset, TableIndex tid)
            : base(th.PEFile, offset, th.GetTableItemSize(tid) * th.GetTableRowCount(tid))
        {
            this.TableIndex = tid;
            this.RowCount = th.GetTableRowCount(tid);
        }

        protected abstract T GetItem(uint offset);
    }

    public class ModuleTableItem : TableItemBase
    {
        public U2Field Generation { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public GuidStreamIndexField Mvid { get; private set; }
        public GuidStreamIndexField EncId { get; private set; }
        public GuidStreamIndexField EncBaseId { get; private set; }

        internal ModuleTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Module)
        {
            var pos = offset;

            this.Generation = new U2Field(this.PEFile, pos);
            pos += this.Generation.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Mvid = new GuidStreamIndexField(this.PEFile, pos);
            pos += this.Mvid.RawDataSize;

            this.EncId = new GuidStreamIndexField(this.PEFile, pos);
            pos += this.EncId.RawDataSize;

            this.EncBaseId = new GuidStreamIndexField(this.PEFile, pos);
            pos += this.EncBaseId.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ModuleTable : TableBase<ModuleTableItem>
    {
        internal ModuleTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Module)
        {
        }

        protected override ModuleTableItem GetItem(uint offset)
        {
            return new ModuleTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class TypeRefTableItem : TableItemBase
    {
        public CodedTokenField ResolutionScope { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public StringsStreamIndexField Namespace { get; private set; }

        internal TypeRefTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.TypeRef)
        {
            var pos = offset;

            this.ResolutionScope = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.ResolutionScope);
            pos += this.ResolutionScope.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Namespace = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Namespace.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class TypeRefTable : TableBase<TypeRefTableItem>
    {
        internal TypeRefTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.TypeRef)
        {
        }

        protected override TypeRefTableItem GetItem(uint offset)
        {
            return new TypeRefTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class TypeDefTableItem : TableItemBase
    {
        public TypeAttributesField Flags { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public StringsStreamIndexField Namespace { get; private set; }
        public CodedTokenField Extends { get; private set; }
        public RidField FieldList { get; private set; }
        public RidField MethodList { get; private set; }

        internal TypeDefTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.TypeDef)
        {
            var pos = offset;

            this.Flags = new TypeAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Namespace = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Namespace.RawDataSize;

            this.Extends = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.TypeDefOrRef);
            pos += this.Extends.RawDataSize;

            this.FieldList = new RidField(this.PEFile, pos, TableIndex.Field);
            pos += this.FieldList.RawDataSize;

            this.MethodList = new RidField(this.PEFile, pos, TableIndex.MethodDef);
            pos += this.MethodList.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class TypeDefTable : TableBase<TypeDefTableItem>
    {
        internal TypeDefTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.TypeDef)
        {
        }

        protected override TypeDefTableItem GetItem(uint offset)
        {
            return new TypeDefTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class FieldPtrTableItem : TableItemBase
    {
        public RidField Field { get; private set; }

        internal FieldPtrTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldPtr)
        {
            var pos = offset;

            this.Field = new RidField(this.PEFile, pos, TableIndex.Field);
            pos += this.Field.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class FieldPtrTable : TableBase<FieldPtrTableItem>
    {
        internal FieldPtrTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldPtr)
        {
        }

        protected override FieldPtrTableItem GetItem(uint offset)
        {
            return new FieldPtrTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class FieldTableItem : TableItemBase
    {
        public FieldAttributesField Flags { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public BlobStreamIndexField Signature { get; private set; }

        internal FieldTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Field)
        {
            var pos = offset;

            this.Flags = new FieldAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Signature = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Signature.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class FieldTable : TableBase<FieldTableItem>
    {
        internal FieldTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Field)
        {
        }

        protected override FieldTableItem GetItem(uint offset)
        {
            return new FieldTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class MethodPtrTableItem : TableItemBase
    {
        public RidField Method { get; private set; }

        internal MethodPtrTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodPtr)
        {
            var pos = offset;

            this.Method = new RidField(this.PEFile, pos, TableIndex.MethodDef);
            pos += this.Method.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class MethodPtrTable : TableBase<MethodPtrTableItem>
    {
        internal MethodPtrTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodPtr)
        {
        }

        protected override MethodPtrTableItem GetItem(uint offset)
        {
            return new MethodPtrTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class MethodDefTableItem : TableItemBase
    {
        public RvaField RVA { get; private set; }
        public MethodImplAttributesField ImplFlags { get; private set; }
        public MethodAttributesField Flags { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public BlobStreamIndexField Signature { get; private set; }
        public RidField ParamList { get; private set; }

        internal MethodDefTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodDef)
        {
            var pos = offset;

            this.RVA = new RvaField(this.PEFile, pos);
            pos += this.RVA.RawDataSize;

            this.ImplFlags = new MethodImplAttributesField(this.PEFile, pos);
            pos += this.ImplFlags.RawDataSize;

            this.Flags = new MethodAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Signature = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Signature.RawDataSize;

            this.ParamList = new RidField(this.PEFile, pos, TableIndex.Param);
            pos += this.ParamList.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class MethodDefTable : TableBase<MethodDefTableItem>
    {
        internal MethodDefTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodDef)
        {
        }

        protected override MethodDefTableItem GetItem(uint offset)
        {
            return new MethodDefTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ParamPtrTableItem : TableItemBase
    {
        public RidField Param { get; private set; }

        internal ParamPtrTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ParamPtr)
        {
            var pos = offset;

            this.Param = new RidField(this.PEFile, pos, TableIndex.Param);
            pos += this.Param.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ParamPtrTable : TableBase<ParamPtrTableItem>
    {
        internal ParamPtrTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ParamPtr)
        {
        }

        protected override ParamPtrTableItem GetItem(uint offset)
        {
            return new ParamPtrTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ParamTableItem : TableItemBase
    {
        public ParamAttributesField Flags { get; private set; }
        public U2Field Sequence { get; private set; }
        public StringsStreamIndexField Name { get; private set; }

        internal ParamTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Param)
        {
            var pos = offset;

            this.Flags = new ParamAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.Sequence = new U2Field(this.PEFile, pos);
            pos += this.Sequence.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ParamTable : TableBase<ParamTableItem>
    {
        internal ParamTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Param)
        {
        }

        protected override ParamTableItem GetItem(uint offset)
        {
            return new ParamTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class InterfaceImplTableItem : TableItemBase
    {
        public RidField Class { get; private set; }
        public CodedTokenField Interface { get; private set; }

        internal InterfaceImplTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.InterfaceImpl)
        {
            var pos = offset;

            this.Class = new RidField(this.PEFile, pos, TableIndex.TypeDef);
            pos += this.Class.RawDataSize;

            this.Interface = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.TypeDefOrRef);
            pos += this.Interface.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class InterfaceImplTable : TableBase<InterfaceImplTableItem>
    {
        internal InterfaceImplTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.InterfaceImpl)
        {
        }

        protected override InterfaceImplTableItem GetItem(uint offset)
        {
            return new InterfaceImplTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class MemberRefTableItem : TableItemBase
    {
        public CodedTokenField Class { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public BlobStreamIndexField Signature { get; private set; }

        internal MemberRefTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MemberRef)
        {
            var pos = offset;

            this.Class = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.MemberRefParent);
            pos += this.Class.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Signature = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Signature.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class MemberRefTable : TableBase<MemberRefTableItem>
    {
        internal MemberRefTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MemberRef)
        {
        }

        protected override MemberRefTableItem GetItem(uint offset)
        {
            return new MemberRefTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ConstantTableItem : TableItemBase
    {
        public U1Field Type { get; private set; }
        public U1Field PaddingZero { get; private set; }
        public CodedTokenField Parent { get; private set; }
        public BlobStreamIndexField Value { get; private set; }

        internal ConstantTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Constant)
        {
            var pos = offset;

            this.Type = new U1Field(this.PEFile, pos);
            pos += this.Type.RawDataSize;

            this.PaddingZero = new U1Field(this.PEFile, pos);
            pos += this.PaddingZero.RawDataSize;

            this.Parent = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.HasConstant);
            pos += this.Parent.RawDataSize;

            this.Value = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Value.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ConstantTable : TableBase<ConstantTableItem>
    {
        internal ConstantTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Constant)
        {
        }

        protected override ConstantTableItem GetItem(uint offset)
        {
            return new ConstantTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class CustomAttributeTableItem : TableItemBase
    {
        public CodedTokenField Parent { get; private set; }
        public CodedTokenField Type { get; private set; }
        public BlobStreamIndexField Value { get; private set; }

        internal CustomAttributeTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.CustomAttribute)
        {
            var pos = offset;

            this.Parent = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.HasCustomAttribute);
            pos += this.Parent.RawDataSize;

            this.Type = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.CustomAttributeType);
            pos += this.Type.RawDataSize;

            this.Value = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Value.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class CustomAttributeTable : TableBase<CustomAttributeTableItem>
    {
        internal CustomAttributeTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.CustomAttribute)
        {
        }

        protected override CustomAttributeTableItem GetItem(uint offset)
        {
            return new CustomAttributeTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class FieldMarshalTableItem : TableItemBase
    {
        public CodedTokenField Parent { get; private set; }
        public BlobStreamIndexField NativeType { get; private set; }

        internal FieldMarshalTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldMarshal)
        {
            var pos = offset;

            this.Parent = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.HasFieldMarshall);
            pos += this.Parent.RawDataSize;

            this.NativeType = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.NativeType.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class FieldMarshalTable : TableBase<FieldMarshalTableItem>
    {
        internal FieldMarshalTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldMarshal)
        {
        }

        protected override FieldMarshalTableItem GetItem(uint offset)
        {
            return new FieldMarshalTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class DeclSecurityTableItem : TableItemBase
    {
        public U2Field Action { get; private set; }
        public CodedTokenField Parent { get; private set; }
        public BlobStreamIndexField PermissionSet { get; private set; }

        internal DeclSecurityTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.DeclSecurity)
        {
            var pos = offset;

            this.Action = new U2Field(this.PEFile, pos);
            pos += this.Action.RawDataSize;

            this.Parent = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.HasDeclSecurity);
            pos += this.Parent.RawDataSize;

            this.PermissionSet = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.PermissionSet.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class DeclSecurityTable : TableBase<DeclSecurityTableItem>
    {
        internal DeclSecurityTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.DeclSecurity)
        {
        }

        protected override DeclSecurityTableItem GetItem(uint offset)
        {
            return new DeclSecurityTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ClassLayoutTableItem : TableItemBase
    {
        public U2Field PackingSize { get; private set; }
        public U4Field ClassSize { get; private set; }
        public RidField Parent { get; private set; }

        internal ClassLayoutTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ClassLayout)
        {
            var pos = offset;

            this.PackingSize = new U2Field(this.PEFile, pos);
            pos += this.PackingSize.RawDataSize;

            this.ClassSize = new U4Field(this.PEFile, pos);
            pos += this.ClassSize.RawDataSize;

            this.Parent = new RidField(this.PEFile, pos, TableIndex.TypeDef);
            pos += this.Parent.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ClassLayoutTable : TableBase<ClassLayoutTableItem>
    {
        internal ClassLayoutTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ClassLayout)
        {
        }

        protected override ClassLayoutTableItem GetItem(uint offset)
        {
            return new ClassLayoutTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class FieldLayoutTableItem : TableItemBase
    {
        public U4Field OffSet { get; private set; }
        public RidField Field { get; private set; }

        internal FieldLayoutTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldLayout)
        {
            var pos = offset;

            this.OffSet = new U4Field(this.PEFile, pos);
            pos += this.OffSet.RawDataSize;

            this.Field = new RidField(this.PEFile, pos, TableIndex.Field);
            pos += this.Field.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class FieldLayoutTable : TableBase<FieldLayoutTableItem>
    {
        internal FieldLayoutTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldLayout)
        {
        }

        protected override FieldLayoutTableItem GetItem(uint offset)
        {
            return new FieldLayoutTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class StandAloneSigTableItem : TableItemBase
    {
        public BlobStreamIndexField Signature { get; private set; }

        internal StandAloneSigTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.StandAloneSig)
        {
            var pos = offset;

            this.Signature = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Signature.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class StandAloneSigTable : TableBase<StandAloneSigTableItem>
    {
        internal StandAloneSigTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.StandAloneSig)
        {
        }

        protected override StandAloneSigTableItem GetItem(uint offset)
        {
            return new StandAloneSigTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class EventMapTableItem : TableItemBase
    {
        public RidField Parent { get; private set; }
        public RidField EventList { get; private set; }

        internal EventMapTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EventMap)
        {
            var pos = offset;

            this.Parent = new RidField(this.PEFile, pos, TableIndex.TypeDef);
            pos += this.Parent.RawDataSize;

            this.EventList = new RidField(this.PEFile, pos, TableIndex.Event);
            pos += this.EventList.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class EventMapTable : TableBase<EventMapTableItem>
    {
        internal EventMapTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EventMap)
        {
        }

        protected override EventMapTableItem GetItem(uint offset)
        {
            return new EventMapTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class EventPtrTableItem : TableItemBase
    {
        public RidField Event { get; private set; }

        internal EventPtrTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EventPtr)
        {
            var pos = offset;

            this.Event = new RidField(this.PEFile, pos, TableIndex.Event);
            pos += this.Event.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class EventPtrTable : TableBase<EventPtrTableItem>
    {
        internal EventPtrTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EventPtr)
        {
        }

        protected override EventPtrTableItem GetItem(uint offset)
        {
            return new EventPtrTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class EventTableItem : TableItemBase
    {
        public EventAttributesField EventFlags { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public CodedTokenField EventType { get; private set; }

        internal EventTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Event)
        {
            var pos = offset;

            this.EventFlags = new EventAttributesField(this.PEFile, pos);
            pos += this.EventFlags.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.EventType = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.TypeDefOrRef);
            pos += this.EventType.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class EventTable : TableBase<EventTableItem>
    {
        internal EventTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Event)
        {
        }

        protected override EventTableItem GetItem(uint offset)
        {
            return new EventTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class PropertyMapTableItem : TableItemBase
    {
        public RidField Parent { get; private set; }
        public RidField PropertyList { get; private set; }

        internal PropertyMapTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.PropertyMap)
        {
            var pos = offset;

            this.Parent = new RidField(this.PEFile, pos, TableIndex.TypeDef);
            pos += this.Parent.RawDataSize;

            this.PropertyList = new RidField(this.PEFile, pos, TableIndex.Property);
            pos += this.PropertyList.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class PropertyMapTable : TableBase<PropertyMapTableItem>
    {
        internal PropertyMapTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.PropertyMap)
        {
        }

        protected override PropertyMapTableItem GetItem(uint offset)
        {
            return new PropertyMapTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class PropertyPtrTableItem : TableItemBase
    {
        public RidField Property { get; private set; }

        internal PropertyPtrTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.PropertyPtr)
        {
            var pos = offset;

            this.Property = new RidField(this.PEFile, pos, TableIndex.Property);
            pos += this.Property.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class PropertyPtrTable : TableBase<PropertyPtrTableItem>
    {
        internal PropertyPtrTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.PropertyPtr)
        {
        }

        protected override PropertyPtrTableItem GetItem(uint offset)
        {
            return new PropertyPtrTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class PropertyTableItem : TableItemBase
    {
        public PropertyAttributesField PropFlags { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public BlobStreamIndexField Type { get; private set; }

        internal PropertyTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Property)
        {
            var pos = offset;

            this.PropFlags = new PropertyAttributesField(this.PEFile, pos);
            pos += this.PropFlags.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Type = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Type.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class PropertyTable : TableBase<PropertyTableItem>
    {
        internal PropertyTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Property)
        {
        }

        protected override PropertyTableItem GetItem(uint offset)
        {
            return new PropertyTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class MethodSemanticsTableItem : TableItemBase
    {
        public MethodSemanticsAttributesField Semantic { get; private set; }
        public RidField Method { get; private set; }
        public CodedTokenField Association { get; private set; }

        internal MethodSemanticsTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodSemantics)
        {
            var pos = offset;

            this.Semantic = new MethodSemanticsAttributesField(this.PEFile, pos);
            pos += this.Semantic.RawDataSize;

            this.Method = new RidField(this.PEFile, pos, TableIndex.MethodDef);
            pos += this.Method.RawDataSize;

            this.Association = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.HasSemantics);
            pos += this.Association.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class MethodSemanticsTable : TableBase<MethodSemanticsTableItem>
    {
        internal MethodSemanticsTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodSemantics)
        {
        }

        protected override MethodSemanticsTableItem GetItem(uint offset)
        {
            return new MethodSemanticsTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class MethodImplTableItem : TableItemBase
    {
        public RidField Class { get; private set; }
        public CodedTokenField MethodBody { get; private set; }
        public CodedTokenField MethodDeclaration { get; private set; }

        internal MethodImplTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodImpl)
        {
            var pos = offset;

            this.Class = new RidField(this.PEFile, pos, TableIndex.TypeDef);
            pos += this.Class.RawDataSize;

            this.MethodBody = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.MethodDefOrRef);
            pos += this.MethodBody.RawDataSize;

            this.MethodDeclaration = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.MethodDefOrRef);
            pos += this.MethodDeclaration.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class MethodImplTable : TableBase<MethodImplTableItem>
    {
        internal MethodImplTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodImpl)
        {
        }

        protected override MethodImplTableItem GetItem(uint offset)
        {
            return new MethodImplTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ModuleRefTableItem : TableItemBase
    {
        public StringsStreamIndexField Name { get; private set; }

        internal ModuleRefTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ModuleRef)
        {
            var pos = offset;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ModuleRefTable : TableBase<ModuleRefTableItem>
    {
        internal ModuleRefTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ModuleRef)
        {
        }

        protected override ModuleRefTableItem GetItem(uint offset)
        {
            return new ModuleRefTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class TypeSpecTableItem : TableItemBase
    {
        public BlobStreamIndexField Signature { get; private set; }

        internal TypeSpecTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.TypeSpec)
        {
            var pos = offset;

            this.Signature = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Signature.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class TypeSpecTable : TableBase<TypeSpecTableItem>
    {
        internal TypeSpecTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.TypeSpec)
        {
        }

        protected override TypeSpecTableItem GetItem(uint offset)
        {
            return new TypeSpecTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ImplMapTableItem : TableItemBase
    {
        public PInvokeAttributesField MappingFlags { get; private set; }
        public CodedTokenField MemberForwarded { get; private set; }
        public StringsStreamIndexField ImportName { get; private set; }
        public RidField ImportScope { get; private set; }

        internal ImplMapTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ImplMap)
        {
            var pos = offset;

            this.MappingFlags = new PInvokeAttributesField(this.PEFile, pos);
            pos += this.MappingFlags.RawDataSize;

            this.MemberForwarded = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.MemberForwarded);
            pos += this.MemberForwarded.RawDataSize;

            this.ImportName = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.ImportName.RawDataSize;

            this.ImportScope = new RidField(this.PEFile, pos, TableIndex.ModuleRef);
            pos += this.ImportScope.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ImplMapTable : TableBase<ImplMapTableItem>
    {
        internal ImplMapTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ImplMap)
        {
        }

        protected override ImplMapTableItem GetItem(uint offset)
        {
            return new ImplMapTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class FieldRvaTableItem : TableItemBase
    {
        public RvaField Rva { get; private set; }
        public RidField Field { get; private set; }

        internal FieldRvaTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldRva)
        {
            var pos = offset;

            this.Rva = new RvaField(this.PEFile, pos);
            pos += this.Rva.RawDataSize;

            this.Field = new RidField(this.PEFile, pos, TableIndex.Field);
            pos += this.Field.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class FieldRvaTable : TableBase<FieldRvaTableItem>
    {
        internal FieldRvaTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.FieldRva)
        {
        }

        protected override FieldRvaTableItem GetItem(uint offset)
        {
            return new FieldRvaTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class EncLogTableItem : TableItemBase
    {
        public U4Field Token { get; private set; }
        public U4Field FuncCode { get; private set; }

        internal EncLogTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EncLog)
        {
            var pos = offset;

            this.Token = new U4Field(this.PEFile, pos);
            pos += this.Token.RawDataSize;

            this.FuncCode = new U4Field(this.PEFile, pos);
            pos += this.FuncCode.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class EncLogTable : TableBase<EncLogTableItem>
    {
        internal EncLogTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EncLog)
        {
        }

        protected override EncLogTableItem GetItem(uint offset)
        {
            return new EncLogTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class EncMapTableItem : TableItemBase
    {
        public U4Field Token { get; private set; }

        internal EncMapTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EncMap)
        {
            var pos = offset;

            this.Token = new U4Field(this.PEFile, pos);
            pos += this.Token.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class EncMapTable : TableBase<EncMapTableItem>
    {
        internal EncMapTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.EncMap)
        {
        }

        protected override EncMapTableItem GetItem(uint offset)
        {
            return new EncMapTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class AssemblyTableItem : TableItemBase
    {
        public AssemblyHashAlgorithmField HashAlgId { get; private set; }
        public U2Field MajorVersion { get; private set; }
        public U2Field MinorVersion { get; private set; }
        public U2Field BuildNumber { get; private set; }
        public U2Field RevisionNumber { get; private set; }
        public AssemblyFlagsField Flags { get; private set; }
        public BlobStreamIndexField PublicKey { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public StringsStreamIndexField Locale { get; private set; }

        internal AssemblyTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Assembly)
        {
            var pos = offset;

            this.HashAlgId = new AssemblyHashAlgorithmField(this.PEFile, pos);
            pos += this.HashAlgId.RawDataSize;

            this.MajorVersion = new U2Field(this.PEFile, pos);
            pos += this.MajorVersion.RawDataSize;

            this.MinorVersion = new U2Field(this.PEFile, pos);
            pos += this.MinorVersion.RawDataSize;

            this.BuildNumber = new U2Field(this.PEFile, pos);
            pos += this.BuildNumber.RawDataSize;

            this.RevisionNumber = new U2Field(this.PEFile, pos);
            pos += this.RevisionNumber.RawDataSize;

            this.Flags = new AssemblyFlagsField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.PublicKey = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.PublicKey.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Locale = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Locale.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class AssemblyTable : TableBase<AssemblyTableItem>
    {
        internal AssemblyTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.Assembly)
        {
        }

        protected override AssemblyTableItem GetItem(uint offset)
        {
            return new AssemblyTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class AssemblyProcessorTableItem : TableItemBase
    {
        public U4Field Processor { get; private set; }

        internal AssemblyProcessorTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyProcessor)
        {
            var pos = offset;

            this.Processor = new U4Field(this.PEFile, pos);
            pos += this.Processor.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class AssemblyProcessorTable : TableBase<AssemblyProcessorTableItem>
    {
        internal AssemblyProcessorTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyProcessor)
        {
        }

        protected override AssemblyProcessorTableItem GetItem(uint offset)
        {
            return new AssemblyProcessorTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class AssemblyOSTableItem : TableItemBase
    {
        public U4Field OSPlatformID { get; private set; }
        public U4Field OSMajorVersion { get; private set; }
        public U4Field OSMinorVersion { get; private set; }

        internal AssemblyOSTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyOS)
        {
            var pos = offset;

            this.OSPlatformID = new U4Field(this.PEFile, pos);
            pos += this.OSPlatformID.RawDataSize;

            this.OSMajorVersion = new U4Field(this.PEFile, pos);
            pos += this.OSMajorVersion.RawDataSize;

            this.OSMinorVersion = new U4Field(this.PEFile, pos);
            pos += this.OSMinorVersion.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class AssemblyOSTable : TableBase<AssemblyOSTableItem>
    {
        internal AssemblyOSTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyOS)
        {
        }

        protected override AssemblyOSTableItem GetItem(uint offset)
        {
            return new AssemblyOSTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class AssemblyRefTableItem : TableItemBase
    {
        public U2Field MajorVersion { get; private set; }
        public U2Field MinorVersion { get; private set; }
        public U2Field BuildNumber { get; private set; }
        public U2Field RevisionNumber { get; private set; }
        public AssemblyFlagsField Flags { get; private set; }
        public BlobStreamIndexField PublicKeyOrToken { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public StringsStreamIndexField Locale { get; private set; }
        public BlobStreamIndexField HashValue { get; private set; }

        internal AssemblyRefTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyRef)
        {
            var pos = offset;

            this.MajorVersion = new U2Field(this.PEFile, pos);
            pos += this.MajorVersion.RawDataSize;

            this.MinorVersion = new U2Field(this.PEFile, pos);
            pos += this.MinorVersion.RawDataSize;

            this.BuildNumber = new U2Field(this.PEFile, pos);
            pos += this.BuildNumber.RawDataSize;

            this.RevisionNumber = new U2Field(this.PEFile, pos);
            pos += this.RevisionNumber.RawDataSize;

            this.Flags = new AssemblyFlagsField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.PublicKeyOrToken = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.PublicKeyOrToken.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Locale = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Locale.RawDataSize;

            this.HashValue = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.HashValue.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class AssemblyRefTable : TableBase<AssemblyRefTableItem>
    {
        internal AssemblyRefTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyRef)
        {
        }

        protected override AssemblyRefTableItem GetItem(uint offset)
        {
            return new AssemblyRefTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class AssemblyRefProcessorTableItem : TableItemBase
    {
        public U4Field Processor { get; private set; }
        public RidField AssemblyRef { get; private set; }

        internal AssemblyRefProcessorTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyRefProcessor)
        {
            var pos = offset;

            this.Processor = new U4Field(this.PEFile, pos);
            pos += this.Processor.RawDataSize;

            this.AssemblyRef = new RidField(this.PEFile, pos, TableIndex.AssemblyRef);
            pos += this.AssemblyRef.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class AssemblyRefProcessorTable : TableBase<AssemblyRefProcessorTableItem>
    {
        internal AssemblyRefProcessorTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyRefProcessor)
        {
        }

        protected override AssemblyRefProcessorTableItem GetItem(uint offset)
        {
            return new AssemblyRefProcessorTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class AssemblyRefOSTableItem : TableItemBase
    {
        public U4Field OSPlatformId { get; private set; }
        public U4Field OSMajorVersion { get; private set; }
        public U4Field OSMinorVersion { get; private set; }
        public RidField AssemblyRef { get; private set; }

        internal AssemblyRefOSTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyRefOS)
        {
            var pos = offset;

            this.OSPlatformId = new U4Field(this.PEFile, pos);
            pos += this.OSPlatformId.RawDataSize;

            this.OSMajorVersion = new U4Field(this.PEFile, pos);
            pos += this.OSMajorVersion.RawDataSize;

            this.OSMinorVersion = new U4Field(this.PEFile, pos);
            pos += this.OSMinorVersion.RawDataSize;

            this.AssemblyRef = new RidField(this.PEFile, pos, TableIndex.AssemblyRef);
            pos += this.AssemblyRef.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class AssemblyRefOSTable : TableBase<AssemblyRefOSTableItem>
    {
        internal AssemblyRefOSTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.AssemblyRefOS)
        {
        }

        protected override AssemblyRefOSTableItem GetItem(uint offset)
        {
            return new AssemblyRefOSTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class FileTableItem : TableItemBase
    {
        public FileAttributesField Flags { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public BlobStreamIndexField HashValue { get; private set; }

        internal FileTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.File)
        {
            var pos = offset;

            this.Flags = new FileAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.HashValue = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.HashValue.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class FileTable : TableBase<FileTableItem>
    {
        internal FileTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.File)
        {
        }

        protected override FileTableItem GetItem(uint offset)
        {
            return new FileTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ExportedTypeTableItem : TableItemBase
    {
        public TypeAttributesField Flags { get; private set; }
        public U4Field TypeDefId { get; private set; }
        public StringsStreamIndexField TypeName { get; private set; }
        public StringsStreamIndexField TypeNamespace { get; private set; }
        public CodedTokenField Implementation { get; private set; }

        internal ExportedTypeTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ExportedType)
        {
            var pos = offset;

            this.Flags = new TypeAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.TypeDefId = new U4Field(this.PEFile, pos);
            pos += this.TypeDefId.RawDataSize;

            this.TypeName = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.TypeName.RawDataSize;

            this.TypeNamespace = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.TypeNamespace.RawDataSize;

            this.Implementation = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.Implementation);
            pos += this.Implementation.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ExportedTypeTable : TableBase<ExportedTypeTableItem>
    {
        internal ExportedTypeTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ExportedType)
        {
        }

        protected override ExportedTypeTableItem GetItem(uint offset)
        {
            return new ExportedTypeTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class ManifestResourceTableItem : TableItemBase
    {
        public U4Field Offset { get; private set; }
        public ManifestResourceAttributesField Flags { get; private set; }
        public StringsStreamIndexField Name { get; private set; }
        public CodedTokenField Implementation { get; private set; }

        internal ManifestResourceTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ManifestResource)
        {
            var pos = offset;

            this.Offset = new U4Field(this.PEFile, pos);
            pos += this.Offset.RawDataSize;

            this.Flags = new ManifestResourceAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            this.Implementation = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.Implementation);
            pos += this.Implementation.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class ManifestResourceTable : TableBase<ManifestResourceTableItem>
    {
        internal ManifestResourceTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.ManifestResource)
        {
        }

        protected override ManifestResourceTableItem GetItem(uint offset)
        {
            return new ManifestResourceTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class NestedClassTableItem : TableItemBase
    {
        public RidField NestedClass { get; private set; }
        public RidField EnclosingClass { get; private set; }

        internal NestedClassTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.NestedClass)
        {
            var pos = offset;

            this.NestedClass = new RidField(this.PEFile, pos, TableIndex.TypeDef);
            pos += this.NestedClass.RawDataSize;

            this.EnclosingClass = new RidField(this.PEFile, pos, TableIndex.TypeDef);
            pos += this.EnclosingClass.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class NestedClassTable : TableBase<NestedClassTableItem>
    {
        internal NestedClassTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.NestedClass)
        {
        }

        protected override NestedClassTableItem GetItem(uint offset)
        {
            return new NestedClassTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class GenericParamTableItem : TableItemBase
    {
        public U2Field Number { get; private set; }
        public GenericParamAttributesField Flags { get; private set; }
        public CodedTokenField Owner { get; private set; }
        public StringsStreamIndexField Name { get; private set; }

        internal GenericParamTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.GenericParam)
        {
            var pos = offset;

            this.Number = new U2Field(this.PEFile, pos);
            pos += this.Number.RawDataSize;

            this.Flags = new GenericParamAttributesField(this.PEFile, pos);
            pos += this.Flags.RawDataSize;

            this.Owner = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.TypeOrMethodDef);
            pos += this.Owner.RawDataSize;

            this.Name = new StringsStreamIndexField(this.PEFile, pos);
            pos += this.Name.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class GenericParamTable : TableBase<GenericParamTableItem>
    {
        internal GenericParamTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.GenericParam)
        {
        }

        protected override GenericParamTableItem GetItem(uint offset)
        {
            return new GenericParamTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class MethodSpecTableItem : TableItemBase
    {
        public CodedTokenField Method { get; private set; }
        public BlobStreamIndexField Instantiation { get; private set; }

        internal MethodSpecTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodSpec)
        {
            var pos = offset;

            this.Method = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.MethodDefOrRef);
            pos += this.Method.RawDataSize;

            this.Instantiation = new BlobStreamIndexField(this.PEFile, pos);
            pos += this.Instantiation.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class MethodSpecTable : TableBase<MethodSpecTableItem>
    {
        internal MethodSpecTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.MethodSpec)
        {
        }

        protected override MethodSpecTableItem GetItem(uint offset)
        {
            return new MethodSpecTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }

    public class GenericParamConstraintTableItem : TableItemBase
    {
        public RidField Owner { get; private set; }
        public CodedTokenField Constraint { get; private set; }

        internal GenericParamConstraintTableItem(TableHeader th, uint offset)
            : base(th, offset, TableIndex.GenericParamConstraint)
        {
            var pos = offset;

            this.Owner = new RidField(this.PEFile, pos, TableIndex.GenericParam);
            pos += this.Owner.RawDataSize;

            this.Constraint = new CodedTokenField(this.PEFile, pos, CodedTokenIndex.TypeDefOrRef);
            pos += this.Constraint.RawDataSize;

            Debug.Assert(pos - offset == this.RawDataSize);
        }
    }

    public class GenericParamConstraintTable : TableBase<GenericParamConstraintTableItem>
    {
        internal GenericParamConstraintTable(TableHeader th, uint offset)
            : base(th, offset, TableIndex.GenericParamConstraint)
        {
        }

        protected override GenericParamConstraintTableItem GetItem(uint offset)
        {
            return new GenericParamConstraintTableItem(this.PEFile.TableStream.TableHeader, offset);
        }
    }
}
